﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Nop.Core;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Plugin.Payments.PayPalExpress.Models;
using Nop.Plugin.Payments.PayPalExpress.PayPalSvc;
using Nop.Plugin.Payments.PayPalExpress.Validators;
using Nop.Services.Configuration;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Web.Framework;
using Nop.Web.Framework.Controllers;
using Nop.Core.Domain.Customers;
using Nop.Services.Authentication;
using Nop.Core.Domain.Common;
using Nop.Services.Messages;
using Nop.Services.Security;

namespace Nop.Plugin.Payments.PayPalExpress.Controllers
{
    public class PaymentPayPalExpressController : BaseNopPaymentController
    {
        private readonly IAuthenticationService _authenticationService;
        private readonly ICountryService _countryService;
        private readonly ISettingService _settingService;
        private readonly IPaymentService _paymentService;
        private readonly IOrderService _orderService;
        private readonly IOrderProcessingService _orderProcessingService;
        private readonly ILogger _logger;
        private readonly IWebHelper _webHelper;
        private readonly PayPalExpressCheckoutPaymentSettings _paypalExpressPaymentSettings;
        private readonly PaymentSettings _paymentSettings;
        private readonly IStateProvinceService _stateProvinceService;
        private readonly OrderSettings _orderSettings;
        private readonly IWorkContext _workContext;
        private readonly CurrencySettings _currencySettings;
        private readonly ICurrencyService _currencyService;
        private readonly ICustomerService _customerService;
        private readonly IOrderTotalCalculationService _orderTotalCalculationService;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IWorkflowMessageService _workflowMessageService;
        private readonly RewardPointsSettings _rewardPointsSettings;
        private readonly IEncryptionService _encryptionService;
        private readonly CustomerSettings _customerSettings;

        public PaymentPayPalExpressController (IAuthenticationService authenticationService,
            ICountryService countryService,
            ISettingService settingService, 
            IPaymentService paymentService, IOrderService orderService, 
            IOrderProcessingService orderProcessingService, 
            ILogger logger, IWebHelper webHelper, PayPalExpressCheckoutPaymentSettings paypalExpressPaymentSettings,
            PaymentSettings paymentSettings, IStateProvinceService stateProvinceService, OrderSettings orderSettings, IWorkContext workContext,
            CurrencySettings currencySettings, ICurrencyService currencyService, ICustomerService customerService, 
            IOrderTotalCalculationService orderTotalCalculationService, IShoppingCartService shoppingCartService,
            IWorkflowMessageService workflowMessageService, RewardPointsSettings rewardPointsSettings, IEncryptionService encryptionService,
            CustomerSettings customerSettings)
        {
            this._authenticationService = authenticationService;
            this._countryService = countryService;
            this._settingService = settingService;
            this._paymentService = paymentService;
            this._orderService = orderService;
            this._orderProcessingService = orderProcessingService;
            this._logger = logger;
            this._webHelper = webHelper;
            this._paypalExpressPaymentSettings = paypalExpressPaymentSettings;
            this._paymentSettings = paymentSettings;
            this._stateProvinceService = stateProvinceService;
            this._orderSettings = orderSettings;
            this._workContext = workContext;
            this._currencySettings = currencySettings;
            this._currencyService = currencyService;
            this._customerService = customerService;
            this._orderTotalCalculationService = orderTotalCalculationService;
            this._shoppingCartService = shoppingCartService;
            this._workflowMessageService = workflowMessageService;
            this._rewardPointsSettings = rewardPointsSettings;
            this._encryptionService = encryptionService;
            this._customerSettings = customerSettings;
        }

        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure()
        {
            var model = new ConfigurationModel();
            model.UseSandbox = _paypalExpressPaymentSettings.UseSandbox;
            //model.BusinessEmail = _paypalExpressPaymentSettings.BusinessEmail;
            model.TransactModeId = Convert.ToInt32(_paypalExpressPaymentSettings.TransactMode);
            model.ApiAccountName = _paypalExpressPaymentSettings.ApiAccountName;
            model.ApiAccountPassword = _paypalExpressPaymentSettings.ApiAccountPassword;
            model.Signature = _paypalExpressPaymentSettings.Signature;
            model.PdtToken = _paypalExpressPaymentSettings.PdtToken;
            model.PdtValidateOrderTotal = _paypalExpressPaymentSettings.PdtValidateOrderTotal;
            model.AdditionalFee = _paypalExpressPaymentSettings.AdditionalFee;
            model.PassProductNamesAndTotals = _paypalExpressPaymentSettings.PassProductNamesAndTotals;
            model.EnableIpn = _paypalExpressPaymentSettings.EnableIpn;
            model.IpnUrl = _paypalExpressPaymentSettings.IpnUrl;
            model.TransactModeValues = _paypalExpressPaymentSettings.TransactMode.ToSelectList();

            return View("Nop.Plugin.Payments.PayPalExpress.Views.PaymentPayPalExpress.Configure", model);
        }

        [HttpPost]
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure(ConfigurationModel model)
        {
            if (!ModelState.IsValid)
                return Configure();

            //save settings
            _paypalExpressPaymentSettings.UseSandbox = model.UseSandbox;
            //_paypalExpressPaymentSettings.BusinessEmail = model.BusinessEmail;
            _paypalExpressPaymentSettings.TransactMode = (TransactMode)model.TransactModeId;
            _paypalExpressPaymentSettings.ApiAccountName = model.ApiAccountName;
            _paypalExpressPaymentSettings.ApiAccountPassword = model.ApiAccountPassword;
            _paypalExpressPaymentSettings.Signature = model.Signature;
            _paypalExpressPaymentSettings.PdtToken = model.PdtToken;
            _paypalExpressPaymentSettings.PdtValidateOrderTotal = model.PdtValidateOrderTotal;
            _paypalExpressPaymentSettings.AdditionalFee = model.AdditionalFee;
            _paypalExpressPaymentSettings.PassProductNamesAndTotals = model.PassProductNamesAndTotals;
            _paypalExpressPaymentSettings.EnableIpn = model.EnableIpn;
            _paypalExpressPaymentSettings.IpnUrl = model.IpnUrl;
            _settingService.SaveSetting(_paypalExpressPaymentSettings);
            model.TransactModeValues = _paypalExpressPaymentSettings.TransactMode.ToSelectList();

            return View("Nop.Plugin.Payments.PayPalExpress.Views.PaymentPayPalExpress.Configure", model);
        }

        [ChildActionOnly]
        public ActionResult PaymentInfo()
        {
            var model = new PaymentInfoModel();
            return View("Nop.Plugin.Payments.PayPalExpress.Views.PaymentPayPalExpress.PaymentInfo", model);
        }

        [NonAction]
        public override IList<string> ValidatePaymentForm(FormCollection form)
        {
            var warnings = new List<string>();
            return warnings;
        }

        [NonAction]
        public override ProcessPaymentRequest GetPaymentInfo(FormCollection form)
        {
            var paymentInfo = new ProcessPaymentRequest();
            return paymentInfo;
        }

        [ValidateInput(false)]
        public ActionResult PDTHandler(FormCollection form)
        {
            string tx = _webHelper.QueryString<string>("tx");
            Dictionary<string, string> values;
            string response;

            var processor = _paymentService.LoadPaymentMethodBySystemName("Payments.PayPalExpress") as PayPalExpressCheckoutPaymentProcessor;
            if (processor == null ||
                !processor.IsPaymentMethodActive(_paymentSettings) || !processor.PluginDescriptor.Installed)
                throw new NopException("PayPal Express module cannot be loaded");

            if (processor.GetPDTDetails(tx, out values, out response))
            {
                string orderNumber = string.Empty;
                values.TryGetValue("custom", out orderNumber);
                Guid orderNumberGuid = Guid.Empty;
                try
                {
                    orderNumberGuid = new Guid(orderNumber);
                }
                catch { }
                Order order = _orderService.GetOrderByGuid(orderNumberGuid);
                if (order != null)
                {
                    decimal total = decimal.Zero;
                    try
                    {
                        total = decimal.Parse(values["mc_gross"], new CultureInfo("en-US"));
                    }
                    catch (Exception exc)
                    {
                        _logger.Error("PayPal PDT. Error getting mc_gross", exc);
                    }

                    string payer_status = string.Empty;
                    values.TryGetValue("payer_status", out payer_status);
                    string payment_status = string.Empty;
                    values.TryGetValue("payment_status", out payment_status);
                    string pending_reason = string.Empty;
                    values.TryGetValue("pending_reason", out pending_reason);
                    string mc_currency = string.Empty;
                    values.TryGetValue("mc_currency", out mc_currency);
                    string txn_id = string.Empty;
                    values.TryGetValue("txn_id", out txn_id);
                    string payment_type = string.Empty;
                    values.TryGetValue("payment_type", out payment_type);
                    string payer_id = string.Empty;
                    values.TryGetValue("payer_id", out payer_id);
                    string receiver_id = string.Empty;
                    values.TryGetValue("receiver_id", out receiver_id);
                    string invoice = string.Empty;
                    values.TryGetValue("invoice", out invoice);
                    string payment_fee = string.Empty;
                    values.TryGetValue("payment_fee", out payment_fee);

                    string address_country = string.Empty;
                    values.TryGetValue("address_country", out address_country);
                    string address_city = string.Empty;
                    values.TryGetValue("address_city", out address_city);
                    string address_country_code = string.Empty;
                    values.TryGetValue("address_country_code", out address_country_code);
                    string address_name = string.Empty;
                    values.TryGetValue("address_name", out address_name);
                    string address_state = string.Empty;
                    values.TryGetValue("address_state", out address_state);
                    string address_status = string.Empty;
                    values.TryGetValue("address_status", out address_status);
                    string address_street = string.Empty;
                    values.TryGetValue("address_street", out address_street);
                    string address_zip = string.Empty;
                    values.TryGetValue("address_zip", out address_zip);
                    string contact_phone = string.Empty;
                    values.TryGetValue("contact_phone", out contact_phone);
                    string first_name = string.Empty;
                    values.TryGetValue("first_name", out first_name);
                    string last_name = string.Empty;
                    values.TryGetValue("last_name", out last_name);

                    var sb = new StringBuilder();
                    sb.AppendLine("Paypal PDT:");
                    sb.AppendLine("total: " + total);
                    sb.AppendLine("Payer status: " + payer_status);
                    sb.AppendLine("Payment status: " + payment_status);
                    sb.AppendLine("Pending reason: " + pending_reason);
                    sb.AppendLine("mc_currency: " + mc_currency);
                    sb.AppendLine("txn_id: " + txn_id);
                    sb.AppendLine("payment_type: " + payment_type);
                    sb.AppendLine("payer_id: " + payer_id);
                    sb.AppendLine("receiver_id: " + receiver_id);
                    sb.AppendLine("invoice: " + invoice);
                    sb.AppendLine("payment_fee: " + payment_fee);

                    //update shipping address
                    order.ShippingAddress.Address1 = address_street;
                    order.ShippingAddress.City = address_city;
                    order.ShippingAddress.StateProvince = _stateProvinceService.GetStateProvinceByAbbreviation(address_state);

                    //order note
                    order.OrderNotes.Add(new OrderNote()
                    {
                        Note = sb.ToString(),
                        DisplayToCustomer = false,
                        CreatedOnUtc = DateTime.UtcNow
                    });
                    _orderService.UpdateOrder(order);

                    //validate order total
                    if (_paypalExpressPaymentSettings.PdtValidateOrderTotal && !Math.Round(total, 2).Equals(Math.Round(order.OrderTotal, 2)))
                    {
                        string errorStr = string.Format("PayPal PDT. Returned order total {0} doesn't equal order total {1}", total, order.OrderTotal);
                        _logger.Error(errorStr);

                        return RedirectToAction("Index", "Home", new { area = "" });
                    }

                    //mark order as paid
                    if (_orderProcessingService.CanMarkOrderAsPaid(order))
                    {
                        order.AuthorizationTransactionId = txn_id;
                        _orderService.UpdateOrder(order);

                        _orderProcessingService.MarkOrderAsPaid(order);
                    }
                }

                return RedirectToRoute("CheckoutCompleted");
            }
            else
            {
                string orderNumber = string.Empty;
                values.TryGetValue("custom", out orderNumber);
                Guid orderNumberGuid = Guid.Empty;
                try
                {
                    orderNumberGuid = new Guid(orderNumber);
                }
                catch { }
                Order order = _orderService.GetOrderByGuid(orderNumberGuid);
                if (order != null)
                {
                    //order note
                    order.OrderNotes.Add(new OrderNote()
                    {
                        Note = "PayPal PDT failed. " + response,
                        DisplayToCustomer = false,
                        CreatedOnUtc = DateTime.UtcNow
                    });
                    _orderService.UpdateOrder(order);
                }
                return RedirectToAction("Index", "Home", new { area = "" });
            }
        }

        [ValidateInput(false)]
        public ActionResult IPNHandler()
        {
            byte[] param = Request.BinaryRead(Request.ContentLength);
            string strRequest = Encoding.ASCII.GetString(param);
            Dictionary<string, string> values;

            var processor = _paymentService.LoadPaymentMethodBySystemName("Payments.PayPalExpress") as PayPalExpressCheckoutPaymentProcessor;
            if (processor == null ||
                !processor.IsPaymentMethodActive(_paymentSettings) || !processor.PluginDescriptor.Installed)
                throw new NopException("PayPal Express module cannot be loaded");

            if (processor.VerifyIPN(strRequest, out values))
            {
                #region values
                decimal total = decimal.Zero;
                try
                {
                    total = decimal.Parse(values["mc_gross"], new CultureInfo("en-US"));
                }
                catch { }

                string payer_status = string.Empty;
                values.TryGetValue("payer_status", out payer_status);
                string payment_status = string.Empty;
                values.TryGetValue("payment_status", out payment_status);
                string pending_reason = string.Empty;
                values.TryGetValue("pending_reason", out pending_reason);
                string mc_currency = string.Empty;
                values.TryGetValue("mc_currency", out mc_currency);
                string txn_id = string.Empty;
                values.TryGetValue("txn_id", out txn_id);
                string txn_type = string.Empty;
                values.TryGetValue("txn_type", out txn_type);
                string rp_invoice_id = string.Empty;
                values.TryGetValue("rp_invoice_id", out rp_invoice_id);
                string payment_type = string.Empty;
                values.TryGetValue("payment_type", out payment_type);
                string payer_id = string.Empty;
                values.TryGetValue("payer_id", out payer_id);
                string receiver_id = string.Empty;
                values.TryGetValue("receiver_id", out receiver_id);
                string invoice = string.Empty;
                values.TryGetValue("invoice", out invoice);
                string payment_fee = string.Empty;
                values.TryGetValue("payment_fee", out payment_fee);

                #endregion

                var sb = new StringBuilder();
                sb.AppendLine("Paypal IPN:");
                foreach (KeyValuePair<string, string> kvp in values)
                {
                    sb.AppendLine(kvp.Key + ": " + kvp.Value);
                }

                var newPaymentStatus = PaypalHelper.GetPaymentStatus(payment_status, pending_reason);
                sb.AppendLine("New payment status: " + newPaymentStatus);

                switch (txn_type)
                {
                    case "recurring_payment_profile_created":
                        //do nothing here
                        break;
                    case "recurring_payment":
                        #region Recurring payment
                        {
                            Guid orderNumberGuid = Guid.Empty;
                            try
                            {
                                orderNumberGuid = new Guid(rp_invoice_id);
                            }
                            catch
                            {
                            }

                            var initialOrder = _orderService.GetOrderByGuid(orderNumberGuid);
                            if (initialOrder != null)
                            {
                                var recurringPayments = _orderService.SearchRecurringPayments(0, initialOrder.Id, null);
                                foreach (var rp in recurringPayments)
                                {
                                    switch (newPaymentStatus)
                                    {
                                        case PaymentStatus.Authorized:
                                        case PaymentStatus.Paid:
                                            {
                                                var recurringPaymentHistory = rp.RecurringPaymentHistory;
                                                if (recurringPaymentHistory.Count == 0)
                                                {
                                                    //first payment
                                                    var rph = new RecurringPaymentHistory()
                                                    {
                                                        RecurringPaymentId = rp.Id,
                                                        OrderId = initialOrder.Id,
                                                        CreatedOnUtc = DateTime.UtcNow
                                                    };
                                                    rp.RecurringPaymentHistory.Add(rph);
                                                    _orderService.UpdateRecurringPayment(rp);
                                                }
                                                else
                                                {
                                                    //next payments
                                                    _orderProcessingService.ProcessNextRecurringPayment(rp);
                                                    //UNDONE change new order status according to newPaymentStatus
                                                    //UNDONE refund/void is not supported
                                                }
                                            }
                                            break;
                                    }
                                }

                                //this.OrderService.InsertOrderNote(newOrder.OrderId, sb.ToString(), DateTime.UtcNow);
                                _logger.Information("PayPal IPN. Recurring info", new NopException(sb.ToString()));
                            }
                            else
                            {
                                _logger.Error("PayPal IPN. Order is not found", new NopException(sb.ToString()));
                            }
                        }
                        #endregion
                        break;
                    default:
                        #region Standard payment
                        {
                            string orderNumber = string.Empty;
                            values.TryGetValue("custom", out orderNumber);
                            Guid orderNumberGuid = Guid.Empty;
                            try
                            {
                                orderNumberGuid = new Guid(orderNumber);
                            }
                            catch
                            {
                            }

                            var order = _orderService.GetOrderByGuid(orderNumberGuid);
                            if (order != null)
                            {

                                //order note
                                order.OrderNotes.Add(new OrderNote()
                                {
                                    Note = sb.ToString(),
                                    DisplayToCustomer = false,
                                    CreatedOnUtc = DateTime.UtcNow
                                });
                                _orderService.UpdateOrder(order);

                                switch (newPaymentStatus)
                                {
                                    case PaymentStatus.Pending:
                                        {
                                        }
                                        break;
                                    case PaymentStatus.Authorized:
                                        {
                                            if (_orderProcessingService.CanMarkOrderAsAuthorized(order))
                                            {
                                                _orderProcessingService.MarkAsAuthorized(order);
                                            }
                                        }
                                        break;
                                    case PaymentStatus.Paid:
                                        {
                                            if (_orderProcessingService.CanMarkOrderAsPaid(order))
                                            {
                                                _orderProcessingService.MarkOrderAsPaid(order);
                                            }
                                        }
                                        break;
                                    case PaymentStatus.Refunded:
                                        {
                                            if (_orderProcessingService.CanRefundOffline(order))
                                            {
                                                _orderProcessingService.RefundOffline(order);
                                            }
                                        }
                                        break;
                                    case PaymentStatus.Voided:
                                        {
                                            if (_orderProcessingService.CanVoidOffline(order))
                                            {
                                                _orderProcessingService.VoidOffline(order);
                                            }
                                        }
                                        break;
                                    default:
                                        break;
                                }
                            }
                            else
                            {
                                _logger.Error("PayPal IPN. Order is not found", new NopException(sb.ToString()));
                            }
                        }
                        #endregion
                        break;
                }
            }
            else
            {
                _logger.Error("PayPal IPN failed.", new NopException(strRequest));
            }

            //nothing should be rendered to visitor
            return Content("");
        }

        public ActionResult SubmitButton()
        {
            try
            {
                //user validation
                //if ((_workContext.CurrentCustomer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed))
                //{
                //    return RedirectToRoute("Login");
                //}

                var cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
                if (cart.Count == 0)
                    return RedirectToRoute("ShoppingCart");

                //USD for US dollars, GBP for British pounds, SEK for Swedish krona, EUR for Euro etc
                var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode;

                if (String.IsNullOrEmpty(_paypalExpressPaymentSettings.ApiAccountName))
                    throw new ApplicationException("PayPal API Account Name is not set");
                if (String.IsNullOrEmpty(_paypalExpressPaymentSettings.ApiAccountPassword))
                    throw new ApplicationException("PayPal API Password is not set");
                if (String.IsNullOrEmpty(_paypalExpressPaymentSettings.Signature))
                    throw new ApplicationException("PayPal API Signature is not set");

                var processor = _paymentService.LoadPaymentMethodBySystemName("Payments.PayPalExpress") as PayPalExpressCheckoutPaymentProcessor;
                if (processor == null ||
                    !processor.IsPaymentMethodActive(_paymentSettings) || !processor.PluginDescriptor.Installed)
                    throw new NopException("PayPal Express Checkout module cannot be loaded");

                var processPaymentRequest = new ProcessPaymentRequest();

                processPaymentRequest.PaymentMethodSystemName = "Payments.PayPalExpress";
                processPaymentRequest.OrderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart) ?? 0;
                processPaymentRequest.IsRecurringPayment = false;
                _workContext.CurrentCustomer.SelectedPaymentMethodSystemName = "Payments.PayPalExpress";
                _customerService.UpdateCustomer(_workContext.CurrentCustomer);
                processPaymentRequest.CustomerId = _workContext.CurrentCustomer.Id;
                this.Session["OrderPaymentInfo"] = processPaymentRequest;

                var resp = processor.SetExpressCheckout(processPaymentRequest, cart);

                if (resp.Ack == AckCodeType.Success)
                {
                    processPaymentRequest.PaypalToken = resp.Token;
                    processPaymentRequest.OrderGuid = new Guid();
                    this.Session["OrderPaymentInfo"] = processPaymentRequest;
                    return new RedirectResult(String.Format(_paypalExpressPaymentSettings.UseSandbox ? "https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token={0}" : "https://www.paypal.com/webscr?cmd=_express-checkout&token={0}", resp.Token));
                }
                else
                {
                    var error = new StringBuilder("We appoligize, but an error has occured.<br />");
                    foreach (var errormsg in resp.Errors)
                    {
                        error.AppendLine(String.Format("{0} | {1} | {2}", errormsg.ErrorCode, errormsg.ShortMessage, errormsg.LongMessage));
                    }
                    return Content(error.ToString());
                }
            }
            catch (Exception exc)
            {
                return Content("Error: " + exc);
            }
        }

        public ActionResult GetDetails(string token)
        {
            var processor = _paymentService.LoadPaymentMethodBySystemName("Payments.PayPalExpress") as PayPalExpressCheckoutPaymentProcessor;
            if (processor == null ||
                !processor.IsPaymentMethodActive(_paymentSettings) || !processor.PluginDescriptor.Installed)
                throw new NopException("PayPal Express Checkout module cannot be loaded");

            var resp = processor.GetExpressCheckoutDetails(token);

            if (resp.Ack == AckCodeType.Success)
            {
                var paymentInfo = this.Session["OrderPaymentInfo"] as ProcessPaymentRequest;
                paymentInfo = processor.SetCheckoutDetails(paymentInfo, resp.GetExpressCheckoutDetailsResponseDetails);
                this.Session["OrderPaymentInfo"] = paymentInfo;
                _workContext.CurrentCustomer = _customerService.GetCustomerById(paymentInfo.CustomerId);
                _customerService.UpdateCustomer(_workContext.CurrentCustomer);

                PayerInfoType payerInfo = resp.GetExpressCheckoutDetailsResponseDetails.PayerInfo;
                var customer=_customerService.GetCustomerByUsername(payerInfo.Payer);
                if (customer != null)/*customer exists*/
                {
                    //update payer's customer Id
                    paymentInfo.CustomerId = customer.Id;
                    this.Session["OrderPaymentInfo"] = paymentInfo;
                    //migrate shopping cart
                    _shoppingCartService.MigrateShoppingCart(_workContext.CurrentCustomer, customer);
                    //login customer now
                    _authenticationService.SignIn(customer, true);
                }
                else
                {
                    /*Save a new record*/
                    var newCustomer = _workContext.CurrentCustomer;
                    newCustomer.Email = payerInfo.Payer;
                    newCustomer.Username = payerInfo.Payer;
                    string saltKey = _encryptionService.CreateSaltKey(5);
                    newCustomer.PasswordSalt = saltKey;
                    newCustomer.Password = _encryptionService.CreatePasswordHash(newCustomer.CustomerGuid.ToString().Substring(0, 4), saltKey, _customerSettings.HashedPasswordFormat);
                    newCustomer.PasswordFormat = PasswordFormat.Hashed;
                    newCustomer.Active = true;

                    //add billingAddress
                    Address billingAddress = new Address();
                    billingAddress.Address1 = payerInfo.Address.Street1;
                    billingAddress.Address2 = payerInfo.Address.Street2;
                    billingAddress.City = payerInfo.Address.CityName;
                    billingAddress.Company = payerInfo.PayerBusiness;
                    billingAddress.CountryId = getCountryId(payerInfo.Address.CountryName);
                    billingAddress.CreatedOnUtc = DateTime.UtcNow;
                    billingAddress.Email = payerInfo.Payer;
                    billingAddress.FirstName = payerInfo.PayerName.FirstName;
                    billingAddress.LastName = payerInfo.PayerName.LastName;
                    billingAddress.PhoneNumber = payerInfo.Address.Phone;
                    billingAddress.StateProvince = getStateProvince(payerInfo.Address.StateOrProvince);
                    billingAddress.StateProvinceId = billingAddress.StateProvince.Id;
                    billingAddress.ZipPostalCode = payerInfo.Address.PostalCode;

                    //add shippingAddress
                    Address shippingAddress = new Address();
                    shippingAddress.Address1 = payerInfo.Address.Street1;
                    shippingAddress.Address2 = payerInfo.Address.Street2;
                    shippingAddress.City = payerInfo.Address.CityName;
                    shippingAddress.Company = payerInfo.PayerBusiness;
                    shippingAddress.CountryId = getCountryId(payerInfo.Address.CountryName);
                    shippingAddress.CreatedOnUtc = DateTime.UtcNow;
                    shippingAddress.Email = payerInfo.Payer;
                    shippingAddress.FirstName = payerInfo.PayerName.FirstName;
                    shippingAddress.LastName = payerInfo.PayerName.LastName;
                    shippingAddress.PhoneNumber = payerInfo.Address.Phone;
                    shippingAddress.StateProvince = getStateProvince(payerInfo.Address.StateOrProvince);
                    shippingAddress.StateProvinceId = billingAddress.StateProvince.Id;
                    shippingAddress.ZipPostalCode = payerInfo.Address.PostalCode;

                    newCustomer.Addresses.Add(billingAddress);
                    newCustomer.Addresses.Add(shippingAddress);

                    newCustomer.SetBillingAddress(billingAddress);
                    newCustomer.SetShippingAddress(shippingAddress);
                    _workContext.CurrentCustomer = newCustomer;
                    _customerService.UpdateCustomer(_workContext.CurrentCustomer);

                    //add to 'Registered' role
                    var registeredRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered);
                    if (registeredRole == null)
                        throw new NopException("'Registered' role could not be loaded");
                    newCustomer.CustomerRoles.Add(registeredRole);
                    //remove from 'Guests' role
                    var guestRole = newCustomer.CustomerRoles.FirstOrDefault(cr => cr.SystemName == SystemCustomerRoleNames.Guests);
                    if (guestRole != null)
                        newCustomer.CustomerRoles.Remove(guestRole);

                    //Add reward points for customer registration (if enabled)
                    if (_rewardPointsSettings.Enabled &&
                        _rewardPointsSettings.PointsForRegistration > 0)
                        newCustomer.AddRewardPointsHistoryEntry(_rewardPointsSettings.PointsForRegistration, "Registered as customer");

                    _workContext.CurrentCustomer = newCustomer;
                    //migrate shopping cart
                    _shoppingCartService.MigrateShoppingCart(_workContext.CurrentCustomer, newCustomer);
                    //send customer welcome message
                    _workflowMessageService.SendCustomerWelcomeMessage(newCustomer, _workContext.WorkingLanguage.Id);
                    //login customer now
                    _authenticationService.SignIn(newCustomer, true);
                    
                }
                return RedirectToRoute("CheckoutShippingMethodPEC");

            }

            return Content("We are sorry - an error occured processing you order<br />");
        }

        public ActionResult CancelOrder(FormCollection form)
        {
            return RedirectToAction("Index", "Home", new { area = "" });
        }

        private int getCountryId (string contryName)
        {
            int ret = 0;
            var countryCollection = _countryService.GetAllCountriesForBilling();
            foreach (var country in countryCollection)
            {
                if (country.Name == contryName)
                {
                    Session["CoutryId"] = country.Id;
                    ret = country.Id;
                }

            }
            return ret;
        }

        private StateProvince getStateProvince (string state)
        {
            StateProvince ret = new StateProvince();
            var stateProvinceCollection = _stateProvinceService.GetStateProvincesByCountryId(Convert.ToInt32(Session["CoutryId"]));
            if (stateProvinceCollection.Count != 0)
            {
                foreach (var stateProvince in stateProvinceCollection)
                {
                    if (stateProvince.Abbreviation == state)
                    {
                        ret = _stateProvinceService.GetStateProvinceById(stateProvince.Id);
                    }

                }
            }
            return ret;

        }
    }
}